const WebSocket = require('ws');
const fs = require('fs');
const path = require('path');
const { OpusEncoder } = require('@discordjs/opus');
const wav = require('node-wav');
const { getMacAddress, TOKEN, ENABLE_TOKEN } = require('./index');

class AudioProcessor {
    constructor(bufferSize = 960) {
        this.bufferSize = bufferSize;
        this.buffer = [];
        this.sampleRate = 16000;
    }

    resetBuffer() {
        this.buffer = [];
    }

    processAudio(inputData) {
        // 输入数据应该是Float32Array格式
        const inputArray = inputData;
        
        // 将新数据添加到缓冲区
        this.buffer = [...this.buffer, ...inputArray];
        
        const chunks = [];
        // 当缓冲区达到指定大小时处理数据
        while (this.buffer.length >= this.bufferSize) {
            // 提取数据
            const chunk = this.buffer.slice(0, this.bufferSize);
            this.buffer = this.buffer.slice(this.bufferSize);
            
            // 转换为16位整数
            const pcmData = Buffer.alloc(chunk.length * 2);
            chunk.forEach((sample, index) => {
                // 限制范围并转换为16位整数
                const intSample = Math.max(-32768, Math.min(32767, Math.floor(sample * 32767)));
                pcmData.writeInt16LE(intSample, index * 2);
            });
            
            chunks.push(pcmData);
        }
        
        return chunks;
    }

    processRemaining() {
        if (this.buffer.length > 0) {
            // 转换为16位整数
            const pcmData = Buffer.alloc(this.buffer.length * 2);
            this.buffer.forEach((sample, index) => {
                const intSample = Math.max(-32768, Math.min(32767, Math.floor(sample * 32767)));
                pcmData.writeInt16LE(intSample, index * 2);
            });
            
            this.buffer = [];
            return [pcmData];
        }
        return [];
    }
}

class WebSocketProxy {
    constructor(proxyPort, targetWsUrl) {
        this.proxyPort = proxyPort;
        this.targetWsUrl = targetWsUrl;
        this.wss = null;
        this.deviceId = getMacAddress();
        this.clientId = this.getClientId();
        this.enableToken = ENABLE_TOKEN;
        this.token = TOKEN;
        
        // 根据token开关设置headers
        this.headers = {
            'Device-Id': this.deviceId,
            'Client-Id': this.clientId,
            'Protocol-Version': '1'
        };
        
        if (this.enableToken) {
            this.headers['Authorization'] = `Bearer ${this.token}`;
        }
        
        this.audioProcessor = new AudioProcessor(960);
        this.audioBuffer = Buffer.alloc(0);
        this.isFirstAudio = true;
        this.totalSamples = 0;
    }

    getClientId() {
        const envPath = path.join(__dirname, '.', '.env');
        let clientId = process.env.CLIENT_ID || '';
        
        if (!clientId) {
            clientId = require('uuid').v4();
            try {
                // 读取当前.env文件内容
                let envContent = '';
                if (fs.existsSync(envPath)) {
                    envContent = fs.readFileSync(envPath, 'utf8');
                }
                
                // 检查是否已存在CLIENT_ID
                if (!envContent.includes('CLIENT_ID=')) {
                    envContent += `\nCLIENT_ID=${clientId}`;
                    fs.writeFileSync(envPath, envContent);
                    process.env.CLIENT_ID = clientId;
                }
            } catch (error) {
                console.error('Failed to save CLIENT_ID:', error);
            }
        }
        
        return clientId;
    }

    createWavHeader(totalSamples) {
        // 创建WAV文件头
        const header = Buffer.alloc(44);
        
        // RIFF header
        header.write('RIFF', 0);
        header.writeUInt32LE(totalSamples * 2 + 36, 4); // File size
        header.write('WAVE', 8);
        
        // fmt chunk
        header.write('fmt ', 12);
        header.writeUInt32LE(16, 16); // Chunk size
        header.writeUInt16LE(1, 20); // Audio format (PCM)
        header.writeUInt16LE(1, 22); // Num channels
        header.writeUInt32LE(16000, 24); // Sample rate
        header.writeUInt32LE(32000, 28); // Byte rate
        header.writeUInt16LE(2, 32); // Block align
        header.writeUInt16LE(16, 34); // Bits per sample
        
        // data chunk
        header.write('data', 36);
        header.writeUInt32LE(totalSamples * 2, 40); // Data size
        
        return header;
    }

    pcmToOpus(pcmData) {
        try {
            // 创建编码器：16kHz, 单声道
            const encoder = new OpusEncoder(16000, 1);
            
            // 编码PCM数据
            // @discordjs/opus期望的数据格式是16位小端序的PCM数据
            const opusData = encoder.encode(pcmData);
            return opusData;
            
        } catch (error) {
            console.error(`Opus编码错误: ${error}, 数据长度: ${pcmData.length}`);
            return null;
        }
    }

    async waitForServerConnection(serverWs, timeoutPromise) {
        // 如果已经连接，直接返回
        if (serverWs.readyState === WebSocket.OPEN) {
            return;
        }
        
        // 创建一个Promise来等待连接打开事件
        const connectionPromise = new Promise((resolve, reject) => {
            // 如果连接已经关闭，直接拒绝
            if (serverWs.readyState === WebSocket.CLOSED || serverWs.readyState === WebSocket.CLOSING) {
                return reject(new Error('连接已关闭或正在关闭'));
            }
            
            // 添加open事件监听器
            const onOpen = () => {
                serverWs.removeListener('open', onOpen);
                serverWs.removeListener('error', onError);
                serverWs.removeListener('close', onClose);
                resolve();
            };
            
            // 添加error事件监听器
            const onError = (error) => {
                serverWs.removeListener('open', onOpen);
                serverWs.removeListener('error', onError);
                serverWs.removeListener('close', onClose);
                reject(error);
            };
            
            // 添加close事件监听器
            const onClose = () => {
                serverWs.removeListener('open', onOpen);
                serverWs.removeListener('error', onError);
                serverWs.removeListener('close', onClose);
                reject(new Error('连接已关闭'));
            };
            
            // 注册事件监听器
            serverWs.once('open', onOpen);
            serverWs.once('error', onError);
            serverWs.once('close', onClose);
        });
        
        // 等待连接建立或超时
        try {
            await Promise.race([connectionPromise, timeoutPromise]);
        } catch (error) {
            // 超时或连接错误，可以选择忽略，因为我们会在调用处检查连接状态
            console.log(`等待连接时发生错误: ${error.message}`);
        }
    }

    async proxyHandler(clientWs, req) {
        console.log(`New client connection from ${req.socket.remoteAddress}`);
        
        let serverWs = null;
        
        try {
            // 连接到远程WebSocket服务器
            // console.log(".............aaa...................",this.targetWsUrl)
            serverWs = new WebSocket(this.targetWsUrl, {
                headers: this.headers
            });
            
            serverWs.on('open', () => {
                console.log(`Connected to server with headers: ${JSON.stringify(this.headers)}`);
            });
            
            serverWs.on('message', async (message) => {
                // console.log("....................xxx............", message);
                
                // 检查消息是否为Buffer类型
                if (Buffer.isBuffer(message)) {
                    try {
                        // 尝试将Buffer转换为字符串，如果成功则视为文本消息
                        const messageStr = message.toString('utf8');
                        
                        // 验证是否为有效的JSON字符串
                        JSON.parse(messageStr);
                        // console.log('服务器发送文本消息，已转换为字符串:', messageStr);
                        
                        // 将转换后的字符串传递给handleServerMessages
                        await this.handleServerMessages(messageStr, clientWs);
                    } catch (error) {
                        // 如果转换或解析失败，则视为二进制消息
                        // console.log('服务器发送二进制消息，直接处理');
                        await this.handleServerMessages(message, clientWs);
                    }
                } else {
                    // 如果不是Buffer，直接处理
                    console.log('服务器发送非Buffer消息');
                    await this.handleServerMessages(message, clientWs);
                }
            });
            
            serverWs.on('close', () => {
                console.log('Server connection closed');
                if (clientWs.readyState === WebSocket.OPEN) {
                    clientWs.close();
                }
            });
            
            serverWs.on('error', (error) => {
                console.error(`Server connection error: ${error}`);
            });
            
            // 处理来自客户端的消息，使用message事件的第二个参数来获取消息类型
            clientWs.on('message', async (message, isBinary) => {
                // console.log("....................yyy............",message, "是否二进制:", isBinary)
                
                // 如果是文本消息且是Buffer，尝试转换为字符串
                if (!isBinary && Buffer.isBuffer(message)) {
                    message = message.toString('utf8');
                }
                // console.log("....................zzz............",message, "serverWs:", serverWs)
                
                await this.handleClientMessages(message, serverWs);
            });
            
            clientWs.on('close', () => {
                console.log('Client connection closed');
                if (serverWs && serverWs.readyState === WebSocket.OPEN) {
                    serverWs.close();
                }
            });
            
            clientWs.on('error', (error) => {
                console.error(`Client connection error: ${error}`);
            });
            
        } catch (error) {
            console.error(`Proxy error: ${error}`);
            if (clientWs.readyState === WebSocket.OPEN) {
                clientWs.close();
            }
        }
    }

    async handleServerMessages(message, clientWs) {
        try {
            if (typeof message === 'string') {
                try {
                    const msgData = JSON.parse(message);
                    
                    // 增加hello消息的日志
                    if (msgData.type === 'hello') {
                        // console.log('服务器返回hello消息:', msgData);
                        // 转发hello消息到客户端
                        clientWs.send(message);
                        return;
                    }
                    
                    if (msgData.type === 'tts' && msgData.state === 'start') {
                        // 新的音频流开始，重置状态
                        if (this.audioBuffer.length > 44) {
                            // 如果还有未播放的数据，先发送
                            const header = Buffer.alloc(44);
                            this.audioBuffer.copy(header, 0, 0, 44);
                            
                            // 更新WAV头中的文件大小和数据大小
                            header.writeUInt32LE(this.totalSamples * 2 + 36, 4);
                            header.writeUInt32LE(this.totalSamples * 2, 40);
                            
                            const completeAudio = Buffer.concat([header, this.audioBuffer.slice(44)]);
                        
                        try {
                            // 发送数据前添加小延迟，确保音频连续性
                            await new Promise(resolve => setTimeout(resolve, 30));
                            clientWs.send(completeAudio);
                        } catch (sendError) {
                            console.error(`音频数据发送错误: ${sendError}`);
                        }
                        }
                        
                        // 完全重置状态
                        this.audioBuffer = Buffer.alloc(0);
                        this.isFirstAudio = true;
                        this.totalSamples = 0;
                    } else if (msgData.type === 'tts' && msgData.state === 'stop') {
                        // 音频流结束，发送剩余数据
                        if (this.audioBuffer.length > 44) {
                            // 更新最终的WAV头
                            const header = Buffer.alloc(44);
                            this.audioBuffer.copy(header, 0, 0, 44);
                            
                            header.writeUInt32LE(this.totalSamples * 2 + 36, 4);
                            header.writeUInt32LE(this.totalSamples * 2, 40);
                            
                            const completeAudio = Buffer.concat([header, this.audioBuffer.slice(44)]);
                            
                            try {
                                // 发送数据前添加小延迟，确保音频连续性
                                await new Promise(resolve => setTimeout(resolve, 50));
                                clientWs.send(completeAudio);
                                
                                // 等待一小段时间确保音频播放完成
                                await new Promise(resolve => setTimeout(resolve, 150));
                            } catch (sendError) {
                                console.error(`音频数据发送错误: ${sendError}`);
                            }
                            
                            // 完全重置状态
                            this.audioBuffer = Buffer.alloc(0);
                            this.isFirstAudio = true;
                            this.totalSamples = 0;
                        }
                    }
                    
                    // 转发消息到客户端
                    clientWs.send(message);
                } catch (e) {
                    // 不是有效的JSON，直接转发
                    clientWs.send(message);
                }
            } else {
                try {
                    // 解码Opus数据
                    const encoder = new OpusEncoder(16000, 1);
                    let pcmData;
                    
                    try {
                        // 尝试解码
                        pcmData = encoder.decode(message);
                    } catch (decodeError) {
                        // 如果解码失败，尝试其他方法
                        console.error(`Opus解码错误: ${decodeError}, 尝试其他方法`);
                        return;
                    }
                    
                    if (pcmData && pcmData.length > 0) {
                        // 计算采样数
                        const samples = pcmData.length / 2; // 16位音频，每个采样2字节
                        this.totalSamples += samples;
                        
                        if (this.isFirstAudio) {
                            // 第一个音频片段，写入WAV头
                            // 第一个音频片段，创建WAV头
                            this.audioBuffer = Buffer.alloc(0); // 确保缓冲区为空
                            this.audioBuffer = Buffer.concat([this.createWavHeader(0), pcmData]); // 先创建空的WAV头
                            this.isFirstAudio = false;
                        } else {
                            // 添加音频数据到已有的缓冲区
                            this.audioBuffer = Buffer.concat([this.audioBuffer, pcmData]);
                        }
                        
                        // 当缓冲区达到一定大小时发送数据 - 减小缓冲区大小以获得更低的延迟
                        if (this.audioBuffer.length >= 16044) { // WAV头(44字节) + 8000个采样(16000字节)
                            // 更新WAV头中的数据大小
                            const header = Buffer.alloc(44);
                            
                            // 重新创建完整的WAV头，确保正确性
                            header.write('RIFF', 0);
                            header.writeUInt32LE(this.totalSamples * 2 + 36, 4); // 文件大小
                            header.write('WAVE', 8);
                            header.write('fmt ', 12);
                            header.writeUInt32LE(16, 16);
                            header.writeUInt16LE(1, 20); // PCM格式
                            header.writeUInt16LE(1, 22); // 单声道
                            header.writeUInt32LE(16000, 24); // 采样率
                            header.writeUInt32LE(32000, 28); // 比特率
                            header.writeUInt16LE(2, 32); // 块对齐
                            header.writeUInt16LE(16, 34); // 采样深度
                            header.write('data', 36);
                            header.writeUInt32LE(this.totalSamples * 2, 40); // 数据大小
                            
                            const completeAudio = Buffer.concat([header, this.audioBuffer.slice(44)]);
                            
                            try {
                                // 发送数据
                                clientWs.send(completeAudio);
                                // 延迟一小段时间确保数据正确发送
                                await new Promise(resolve => setTimeout(resolve, 50));
                            } catch (sendError) {
                                console.error(`音频数据发送错误: ${sendError}`);
                            }
                            
                            // 完全重置缓冲区
                            this.audioBuffer = Buffer.alloc(0);
                            this.isFirstAudio = true;
                            this.totalSamples = 0;
                        }
                    }
                } catch (error) {
                    console.error(`音频处理错误: ${error}`);
                }
            }
        } catch (error) {
            console.error(`Server message handling error: ${error}`);
        }
    }

    async handleClientMessages(message, serverWs) {
        // console.log(".............客户端发送消息.............",message)
        try {
            // 首先尝试将Buffer消息转换为字符串处理
            // let messageStr = null;
            // if (Buffer.isBuffer(message)) {
                try {
                    // messageStr = message.toString('utf8');
                    const msgData = JSON.parse(message);
                    
                    // 增加hello消息的日志
                    if (msgData.type === 'hello') {
                        // console.log('客户端发送hello消息:', msgData);
                        // 转发hello消息到服务器
                        if (serverWs.readyState === WebSocket.OPEN) {
                            // console.log('转发hello消息到远程服务器');
                            serverWs.send(message);
                        } else {
                            // console.log('服务器连接未打开，等待连接建立后发送hello消息...');
                            // 等待服务器连接建立，最多等待5秒
                            const waitTimeout = new Promise((resolve, reject) => {
                                setTimeout(() => reject(new Error('连接超时')), 5000);
                            });
                            
                            // 等待服务器连接打开
                            await this.waitForServerConnection(serverWs, waitTimeout);
                            
                            // 如果连接已建立，发送hello消息
                            if (serverWs.readyState === WebSocket.OPEN) {
                                console.log('服务器连接已建立，发送hello消息');
                                serverWs.send(message);
                            } else {
                                console.log('警告: 等待超时或服务器连接仍未打开');
                            }
                        }
                        return; // 已处理hello消息，返回
                    } else if (msgData.type === 'reset') {
                        this.audioProcessor.resetBuffer();
                        return; // 已处理reset消息，返回
                    } else if (msgData.type === 'getLastData') {
                        // 处理剩余数据
                        const remainingChunks = this.audioProcessor.processRemaining();
                        for (const chunk of remainingChunks) {
                            const opusData = this.pcmToOpus(chunk);
                            if (opusData && serverWs.readyState === WebSocket.OPEN) {
                                serverWs.send(opusData);
                            }
                        }
                        // 发送处理完成消息
                        if (serverWs.readyState === WebSocket.OPEN) {
                            serverWs.send(JSON.stringify({ type: 'lastData' }));
                        }
                        return; // 已处理getLastData消息，返回
                    } else {
                        // 转发其他JSON消息到服务器
                        if (serverWs.readyState === WebSocket.OPEN) {
                            serverWs.send(message);
                        }
                        return; // 已处理其他JSON消息，返回
                    }
                } catch (e) {
                    // 不是有效的JSON字符串，继续处理为二进制音频数据
                    console.log('消息不是有效的JSON，将作为二进制数据处理');
                }
            // }
            
            // 处理字符串类型的消息
            if (typeof message === 'string') {
                try {
                    const msgData = JSON.parse(message);
                    
                    // 增加hello消息的日志
                    if (msgData.type === 'hello') {
                        console.log('客户端发送hello消息:', msgData);
                        // 转发hello消息到服务器
                        if (serverWs.readyState === WebSocket.OPEN) {
                            console.log('转发hello消息到远程服务器');
                            serverWs.send(message);
                        } else {
                            console.log('警告: 服务器连接未打开，无法转发hello消息');
                        }
                    } else if (msgData.type === 'reset') {
                        this.audioProcessor.resetBuffer();
                    } else if (msgData.type === 'getLastData') {
                        // 处理剩余数据
                        const remainingChunks = this.audioProcessor.processRemaining();
                        for (const chunk of remainingChunks) {
                            const opusData = this.pcmToOpus(chunk);
                            if (opusData && serverWs.readyState === WebSocket.OPEN) {
                                serverWs.send(opusData);
                            }
                        }
                        // 发送处理完成消息
                        if (serverWs.readyState === WebSocket.OPEN) {
                            serverWs.send(JSON.stringify({ type: 'lastData' }));
                        }
                    } else {
                        // 转发消息到服务器
                        if (serverWs.readyState === WebSocket.OPEN) {
                            serverWs.send(message);
                        }
                    }
                } catch (e) {
                    // 不是有效的JSON，直接转发
                    if (serverWs.readyState === WebSocket.OPEN) {
                        serverWs.send(message);
                    }
                }
            } else {
                // 处理二进制音频数据
                try {
                    // 确保数据是Buffer格式
                    const audioData = message instanceof Buffer ? message : Buffer.from(message);
                    
                    // 假设音频数据是Float32Array格式
                    const float32Array = new Float32Array(audioData.buffer, audioData.byteOffset, audioData.byteLength / 4);
                    
                    if (float32Array.length > 0) {
                        // 使用AudioProcessor处理音频数据
                        const chunks = this.audioProcessor.processAudio(float32Array);
                        
                        for (const chunk of chunks) {
                            const opusData = this.pcmToOpus(chunk);
                            if (opusData && serverWs.readyState === WebSocket.OPEN) {
                                serverWs.send(opusData);
                            } else {
                                console.log('音频编码失败或服务器连接已关闭');
                            }
                        }
                    } else {
                        console.log('收到空的音频数据');
                    }
                } catch (error) {
                    console.error(`音频处理错误: ${error}`);
                }
            }
        } catch (error) {
            console.error(`Client message handling error: ${error}`);
        }
    }

    start() {
        // 创建WebSocket服务器
        this.wss = new WebSocket.Server({
            port: this.proxyPort,
            host: '0.0.0.0',
            perMessageDeflate: false,
            maxPayload: 10485760 // 10MB
        });
        
        this.wss.on('connection', (ws, req) => {
            // 配置WebSocket实例的binaryType属性为'blob'，使其以字符串形式处理文本消息
            ws.binaryType = 'blob';
            this.proxyHandler(ws, req);
        });
        
        this.wss.on('error', (error) => {
            console.error(`WebSocket server error: ${error}`);
        });
        
        console.log(`Starting proxy server on 0.0.0.0:${this.proxyPort}`);
        console.log(`Device ID: ${this.deviceId}`);
        console.log(`Token: ${this.token}`);
        console.log(`Target WS URL: ${this.targetWsUrl}`);
    }

    close() {
        if (this.wss) {
            this.wss.close(() => {
                console.log('Proxy server closed');
            });
        }
    }
}

module.exports = WebSocketProxy;

// 如果直接运行此文件，则启动代理服务器
if (require.main === module) {
    const PROXY_PORT = parseInt(process.env.PROXY_PORT || '5002');
    const WS_URL = process.env.WS_URL || 'ws://localhost:9005';
    
    const proxy = new WebSocketProxy(PROXY_PORT, WS_URL);
    proxy.start();
}